using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace CPI311.GameEngine
{
    public class AnimatedSprite : Sprite
    {
        public int FrameWidth {get; protected set;}
        public int FrameHeight {get; protected set;}
        public int TotalHeight {get; protected set;}
        public int TotalWidth {get; protected set;}
        public int Frames {get; protected set;}
        public int currentFrame {get; protected set;}
        public Animation currentAnimation {get; protected set;}
        public List<Animation> Animations {get; protected set;}

        public AnimatedSprite(Texture2D texture, int frameWidth, int frameHeight, int totalHeight, int totalWidth, int frames, List<Animation> animations, Vector2 position) :base(texture, position)
        {
            Animations = animations;
            currentAnimation = Animations[0];
            FrameHeight = frameHeight;
            FrameWidth = frameWidth;
            Frames = frames;
            currentFrame = 0;
        }
                
        //Function findFrame(int i, int row):Tuple<int,int>
        //Description: given a frame of the total 
        //parameters - i:desired frame
        //           - row:row of frame (should be zero when you call function)
        //returns - Tuple<int,int>: the top left corner of the desired frame
        public Tuple<int, int> findFrame(int i, int row)
        {
            if(i == 0)
                return new Tuple<int, int>(0,row * FrameHeight);
            if(i * FrameWidth > TotalWidth)
            {
                i -= (TotalWidth/FrameWidth);
                row++;
                return findFrame(i,row);
            }
            else
            {
                return new Tuple<int, int>(i*FrameWidth, row*FrameHeight);
            }
        }

        //Function setAnimation(int):void
        //Description:  changes the current animation to the given animation index
        //              does not change animation if index does not exist
        //Parameters:   index: index of the desired animation
        //Returns:      None
        public void setAnimation(int index)
        {
            try
            {
                currentAnimation = Animations[index];
            }
            catch(Exception ex)
            {
                ErrorHandler.logError(ex.Message);
            }
        }

        //Function setAnimation(string animation):void
        //Description:  changes the current animation to the given animation name
        //              does not change animation if name does not exist
        //Parameters:   animation: Name of the desired animation
        //Returns:      None
        public void setAnimation(string animation)
        {
            try
            {
                Animation temp = currentAnimation;
                currentAnimation = null;
                foreach(Animation anim in Animations)
                {
                    if(anim.Name == animation)
                    {
                        currentAnimation = anim;
                    }
                }
                if(currentAnimation == null)
                {
                    throw(new Exception("animation " + animation + " not found"));
                }
                currentFrame = 0;
            }
            catch(Exception ex)
            {
                ErrorHandler.logError(ex.Message);
            }

        }
        //Function nextFrame()
        //Desciption: sets the source rectangle for the texture to the next frame
        //            of the current animation
        //Parameters: none
        //Returns: none
        public void nextFrame()
        {
            currentFrame++;
            if(currentFrame > currentAnimation.Frames)
            {
                currentFrame = 0;
            }
            Tuple<int,int> newSource = findFrame(currentFrame + currentAnimation.StartFrame, 0);
            Source = new Rectangle(newSource.Item1, newSource.Item2, newSource.Item1 * FrameWidth, newSource.Item2 * FrameHeight);
        }

        //Function goToFrame(int index)
        //Description:  Goes to the specified frame of the current animation
        //              if specified frame is over the total frames will reduce
        //              frame to be within limits
        //              Also sets the index to be the current frame
        //Parameters:   index: index of desired frame
        //Returns:      none
        public void goToFrame(int index)
        {
            index = index % currentAnimation.Frames;            
            Tuple<int,int> newSource = findFrame(index + currentAnimation.StartFrame, 0);
            Source = new Rectangle(newSource.Item1, newSource.Item2, newSource.Item1 * FrameWidth, newSource.Item2 * FrameHeight);
            currentFrame = index;
        }

        public void update()
        {
            float temp = Time.ElapsedGameTime;
            while(temp > 0.03)
            {
                nextFrame();
                temp -= 0.03f;
            }
        }
    }
}
